package com.yf.mediaserver.gb.cmd;

import cn.hutool.core.util.RandomUtil;
import com.yf.mediaserver.gb.config.SipConfig;
import com.yf.mediaserver.gb.sip.SipLayer;
import com.yf.mediaserver.gb.sip.processors.SIPSender;
import com.yf.mediaserver.gb.sip.util.SipUtils;
import gov.nist.javax.sip.message.SIPResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sip.InvalidArgumentException;
import javax.sip.PeerUnavailableException;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.ArrayList;

/**
 * request创造器
 */
@Slf4j
@Component
public class SIPRequestHeaderProvider {


    @Resource
    private SipLayer sipLayer;


    @Resource
    private SipConfig sipConfig;

    @Resource
    private SIPSender sipSender;

    private static AddressFactory ADDRESS_FACTORY;
    private static HeaderFactory HEADER_FACTORY;
    private static MessageFactory MESSAGE_FACTORY;

    public static final String DATA_FORMAT = "yyyy-MM-dd'T'hh:mm:ss";

    static {
        init();
    }

    @SneakyThrows
    public static void init() {
        SipFactory sipFactory = SipFactory.getInstance();
        HEADER_FACTORY = sipFactory.createHeaderFactory();
        ADDRESS_FACTORY = sipFactory.createAddressFactory();
        MESSAGE_FACTORY = sipFactory.createMessageFactory();
    }


    @SneakyThrows
    public void sendInviteRespACK( SIPResponse response, String channelId, String deviceAddr){

        String requestType  =Request.ACK;

        Request request = MESSAGE_FACTORY.createRequest(
                //sip:媒体流发送者设备编码@目的域名或IP地址端口SIP/2.0
                getSipURI(channelId, deviceAddr),
                requestType,
                response.getCallIdHeader(),
                getcSeqHeader(response, requestType),
                //<sip:媒体流接收者设备编码@源域名>
                response.getFromHeader(),
                //sip:媒体流发送者设备编码@目的域名
                response.getToHeader(),
                //SIP/2.0/UDP 源域名或IP地址
                getViaHeaders(sipConfig.getIp(),sipConfig.getPort(),response.getTopmostViaHeader().getTransport()),
//                getViaHeaders(sipLayer.getLocalIp(null),sipConfig.getPort(),transport),
                getMaxForwardsHeader()
        );

        addUserAgent(request);
        addContactHeader(sipConfig.getId(),sipConfig.getAddr(), request);
        sipSender.simpleSend(sipLayer.getLocalIp(null),request);
    }

    @SneakyThrows
    public void sendInviteRequest(
            String channelId, String sipServerAddr, String deviceAddr,String content, String ssrc
    ) {

        String requestType = Request.INVITE;
        String transport = "UDP";
        Request request = MESSAGE_FACTORY.createRequest(
                //sip:媒体流发送者设备编码@目的域名或IP地址端口SIP/2.0
                getSipURI(channelId, deviceAddr),
                requestType,
                sipLayer.getUdpSipProvider().getNewCallId(),
                getcSeqHeader(RandomUtil.randomLong(1000), requestType),
                //<sip:媒体流接收者设备编码@源域名>
                getFromHeader(sipConfig.getId(),sipConfig.getDomain()),
                //sip:媒体流发送者设备编码@目的域名
                getToHeader(channelId, deviceAddr,false),
                //SIP/2.0/UDP 源域名或IP地址
                getViaHeaders(sipLayer.getLocalIp(null),sipConfig.getPort(),transport),
                getMaxForwardsHeader(),
                getSDPContentTypeHeader(),
                content
        );

        //Contact
        addUserAgent(request);
        //Contact
//        <sip:媒体流接收者设备编码@源IP地址端口>
        addContactHeader(sipConfig.getId(),sipServerAddr, request);
        // Subject
        addSubjectHeader(channelId, ssrc, sipConfig.getId(),request);

        sipSender.simpleSend(sipLayer.getLocalIp(null),request);
    }


    private static void addUserAgent(Request request) throws PeerUnavailableException, ParseException {
        //User-Agent: WVP-Pro
        request.addHeader(SipUtils.createUserAgentHeader());
    }


    private static ContentTypeHeader getMANSCDPContentTypeHeader() throws ParseException {
        return getContentTypeHeader("MANSCDP+xml");
    }

    private static ContentTypeHeader getSDPContentTypeHeader() throws ParseException {
        return getContentTypeHeader("SDP");
    }


    private static ContentTypeHeader getContentTypeHeader(String v) throws ParseException {
        return HEADER_FACTORY.createContentTypeHeader("APPLICATION", v);
    }

    private static MaxForwardsHeader getMaxForwardsHeader() throws InvalidArgumentException {
        // Max-Forwards: 70
        return HEADER_FACTORY.createMaxForwardsHeader(70);
    }

    /**
     *
     * SIP/2.0/UDP 源域名或IP地址
     * Via: SIP/2.0/UDP 192.168.1.59:5060;branch=z9hG4bK1703657106715;rport
     * @param sipServerId  源域名
     * @param port  源端口
     * @param transport 协议
     */
    @SneakyThrows
    private ArrayList<ViaHeader> getViaHeaders(String sipServerId,int port ,String transport )  {
        // Via
        ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
        // SipLayer.getLocalIp(DEVICE_LOCAL) ->  192.168.1.59:5060
        // viaTag ->  z9hG4bK1703584545187
        // 结果
        // Via: SIP/2.0/UDP 192.168.1.59:5060;branch=z9hG4bK1703584545187
        ViaHeader viaHeader = HEADER_FACTORY.createViaHeader(sipServerId, port, transport, SipUtils.getNewViaTag());
        // Via: SIP/2.0/UDP 192.168.1.59:5060;branch=z9hG4bK1703584545187;rport
        viaHeader.setRPort();
        viaHeaders.add(viaHeader);
        return viaHeaders;
    }

    /**
     * //sip:媒体流发送者设备编码@目的域名
     * To: &lt;sip:34020000001320000001@192.168.1.64:5060&gt
     * @param deviceId 媒体流发送者设备编码
     * @param deviceAddr 目的域名
     * @param hasTag 需要 Tag
     */
    @SneakyThrows
    private ToHeader getToHeader(String deviceId, String deviceAddr,boolean hasTag) throws ParseException {
        // To
        //sip:34020000001320000001@192.168.1.64:5060
        SipURI toSipURI = getSipURI(deviceId, deviceAddr);
        //<sip:34020000001320000001@192.168.1.64:5060>
        Address toAddress = ADDRESS_FACTORY.createAddress(toSipURI);
        //<sip:34020000001320000001@192.168.1.64:5060>;tag=111
        return HEADER_FACTORY.createToHeader(toAddress, hasTag?SipUtils.getNewTag():null);
    }

    /**
     * &lt;sip:媒体流接收者设备编码@源域名&gt
     * From: &lt;sip:34020000001000000001@3402000000&gt;tag=bfd48009c1194a7ab81a34797cebee31
     * @param sipId 媒体流接收者设备编码
     * @param sipDomain 源域名
     */
    @SneakyThrows
    private FromHeader getFromHeader(String sipId,String sipDomain) throws ParseException {
        //sip:34020000001000000001@3402000000
        SipURI fromSipURI = ADDRESS_FACTORY.createSipURI(sipId, sipDomain);
        //<sip:34020000001000000001@3402000000>
        Address address = ADDRESS_FACTORY.createAddress(fromSipURI);
        //<sip:34020000001000000001@3402000000>;tag=5d90feded7ef4fe88442d4f7ea218823
        return HEADER_FACTORY.createFromHeader(address, SipUtils.getNewFromTag());
    }



    @SneakyThrows
    private CSeqHeader getcSeqHeader(SIPResponse response,String requestType ){
        //CSeq: 1 MESSAGE
//        return headerFactory.createCSeqHeader(CSEQ, Request.MESSAGE);
        return HEADER_FACTORY.createCSeqHeader(response.getCSeqHeader().getSeqNumber(), requestType);
    }

    @SneakyThrows
    private CSeqHeader getcSeqHeader(long cesq, String requestType) throws ParseException, InvalidArgumentException {
        //CSeq: 1 MESSAGE
//        return headerFactory.createCSeqHeader(CSEQ, Request.MESSAGE);
        return HEADER_FACTORY.createCSeqHeader(cesq, requestType);
    }

    /**
     * sip:媒体流发送者设备编码@目的域名或IP地址端口SIP/2.0
     * sip:34020000001320000001@192.168.1.64:5060 SIP/2.0
     * @param deviceId 媒体流发送者设备编码
     * @param deviceAddr 目的域名或IP地址端口SIP
     */
    @SneakyThrows
    private SipURI getSipURI(String deviceId, String deviceAddr)  {
        return ADDRESS_FACTORY.createSipURI(deviceId, deviceAddr);
    }

    /**
     * Subject: 媒体流发送者设备编码:发送端媒体流序列号,媒体流接收者设备编码:接收端媒体流序列号
     * 示例：Subject: 34020000001320000001:0200000965,34020000001000000001:0
     * @param channelId 媒体流发送者设备编码
     * @param ssrc 发送端媒体流序列号
     * @param sipId 媒体流接收者设备编码
     * @param request request
     *
     */
    @SneakyThrows
    private void addSubjectHeader(String channelId, String ssrc,String sipId, Request request){
        SubjectHeader subjectHeader = HEADER_FACTORY.createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipId, 0));
        request.addHeader(subjectHeader);
    }

    /**
     *  &lt;sip:媒体流接收者设备编码@源IP地址端口&gt
     *  示例：Contact: &lt;sip:34020000001000000001@192.168.1.59:5060&gt
     * @param sipId 媒体流接收者设备编码
     * @param sipServerAddr 源IP地址端口
     * @param request request
     */
    @SneakyThrows
    private void addContactHeader(String sipId,String sipServerAddr, Request request) {
        //<sip:媒体流接收者设备编码@源IP地址端口>
        Address concatAddress = ADDRESS_FACTORY.createAddress(ADDRESS_FACTORY.createSipURI(sipId, sipServerAddr));
        request.addHeader(HEADER_FACTORY.createContactHeader(concatAddress));
    }


}
